package com.tuandai.commons.encrypt.jdbc_api;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * Created by zhangzhenbin on 17-7-24.
 */
public class DbPasswordDigestUtils {
    private static final String KEY_ALGORITHM = "RSA";
    private static final int KEY_SIZE = 512;
    private static final int ENCRYPT_BlOCK_SIZE = KEY_SIZE / 8 - 11;
    private static final int DECRYPT_BLOCK_SIZE = KEY_SIZE / 8;
    private static String PUBLIC_KEY="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJd9C1kok1cPvlh2BfONBiOOJ0Pj5n1dzzOSi0PR+8Tp9geNIUtKpIAvZg671XKBvRuPEZDQhIpxvsk0Y93UicECAwEAAQ==";
    private static String PRIVATE_KEY="MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAl30LWSiTVw++WHYF840GI44nQ+PmfV3PM5KLQ9H7xOn2B40hS0qkgC9mDrvVcoG9G48RkNCEinG+yTRj3dSJwQIDAQABAkBIftPmeA+C04rxBJI2ip+MdmP+DltoVXNqJ9AzxZKqGdhq4zGCOzXxyZkqCn2n9r7bg+OoDK5QFrYzW9q9rciNAiEA8bBOQfBW9OOW7T69d8KEzJ9OYFDORaMzrDANW/6/Hd8CIQCgdWrVF3E5OzAwPA8/muBnoYp/BMNAu8saCKCHTL4MXwIgY29I0yIhdIFKL/N3GhWCc3k7Uq8MHmRltvrSFD47vPsCIH/YDZ5qZxOqTOKhd6S9yT3IP4ikSs0w0smTRhOG2YURAiA24bW9Q/0rvzigHlNL8mSvBRtyCsKWY2vuKb/QTBnM2A==";

    /**
     * 加密
     *
     * @param encryptStr
     * @return
     * @throws Exception
     */
    public static String encrypt(String encryptStr) throws Exception {
        byte[] publicKeyBytes = Base64.decodeBase64(PUBLIC_KEY);
        byte[] encryptBytes = encryptStr.getBytes("UTF-8");

        if (encryptBytes.length <= ENCRYPT_BlOCK_SIZE) {
            return Base64.encodeBase64String(encrypt(encryptBytes, publicKeyBytes));
        } else {
            byte[] buffer = null;
            byte[] blockBytes = new byte[ENCRYPT_BlOCK_SIZE];

            int index = ((encryptBytes.length - 1) / ENCRYPT_BlOCK_SIZE) + 1;

            for (int i = 0; i < index; i++) {
                if (i == (index - 1)) {
                    blockBytes = new byte[ENCRYPT_BlOCK_SIZE];
                }
                int startIndex = i * ENCRYPT_BlOCK_SIZE;
                int endIndex = startIndex + ENCRYPT_BlOCK_SIZE;
                blockBytes = ArrayUtils.subarray(encryptBytes, startIndex, endIndex);
                if (buffer == null) {
                    buffer = encrypt(blockBytes, publicKeyBytes);
                } else {
                    buffer = ArrayUtils.addAll(buffer, encrypt(blockBytes, publicKeyBytes));
                }

            }
            return Base64.encodeBase64String(buffer);
        }
    }

    /**
     * 解密
     *
     * @param decryptStr
     * @return
     * @throws Exception
     */
    public static String decrypt(String decryptStr) throws Exception {
        byte[] privateKeyBytes = Base64.decodeBase64(PRIVATE_KEY);

        byte[] decryptBytes = Base64.decodeBase64(decryptStr);

        if (decryptBytes.length <= DECRYPT_BLOCK_SIZE) {
            return new String(decrypt(decryptBytes, privateKeyBytes), "UTF-8");
        } else {
            byte[] buffer = null;

            int index = ((decryptBytes.length - 1) / DECRYPT_BLOCK_SIZE) + 1;
            byte[] blockBytes = new byte[DECRYPT_BLOCK_SIZE];
            for (int i = 0; i < index; i++) {
                if (i == index - 1) {
                    blockBytes = new byte[DECRYPT_BLOCK_SIZE];
                }
                int startIndex = i * DECRYPT_BLOCK_SIZE;
                int endIndex = startIndex + DECRYPT_BLOCK_SIZE;
                blockBytes = ArrayUtils.subarray(decryptBytes, startIndex, endIndex > decryptBytes.length ? decryptBytes.length : endIndex);
                if (buffer == null) {
                    buffer = decrypt(blockBytes, privateKeyBytes);
                } else {
                    buffer = ArrayUtils.addAll(buffer, decrypt(blockBytes, privateKeyBytes));
                }
            }
            return new String(buffer, "UTF-8");
        }
    }

    /**
     * 加密
     *
     * @param encryptBytes
     * @param publicKeyBytes
     * @return
     * @throws Exception
     */
    private static byte[] encrypt(byte[] encryptBytes, byte[] publicKeyBytes) throws Exception {
        PublicKey publicKey = DbPasswordDigestUtils.codeToPublicKey(publicKeyBytes);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] enBytes = cipher.doFinal(encryptBytes);
        return enBytes;
    }

    /**
     * 解密
     *
     * @param decrypt
     * @param privateKeyBytes
     * @return
     * @throws Exception
     */
    private static byte[] decrypt(byte[] decrypt, byte[] privateKeyBytes) throws Exception {
        PrivateKey privateKey = DbPasswordDigestUtils.codeToPrivateKey(privateKeyBytes);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] resultBytes = cipher.doFinal(decrypt);
        return resultBytes;
    }

    private static PublicKey codeToPublicKey(byte[] publicKey) throws Exception {
        //x.509,是x500那套网络协议（好像是目录协议吧）的一个子集，专门定义了在目录访问中需要身份认证的证书的格式。
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generatePublic(keySpec);
    }

    private static PrivateKey codeToPrivateKey(byte[] privateKey) throws Exception {
        //PKCS#8：描述私有密钥信息格式，该信息包括公开密钥算法的私有密钥以及可选的属性集等。
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey keyPrivate = keyFactory.generatePrivate(keySpec);
        return keyPrivate;
    }

    public static void main(String[] args) throws Exception {
        PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJd9C1kok1cPvlh2BfONBiOOJ0Pj5n1dzzOSi0PR+8Tp9geNIUtKpIAvZg671XKBvRuPEZDQhIpxvsk0Y93UicECAwEAAQ==";
        PRIVATE_KEY = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAl30LWSiTVw++WHYF840GI44nQ+PmfV3PM5KLQ9H7xOn2B40hS0qkgC9mDrvVcoG9G48RkNCEinG+yTRj3dSJwQIDAQABAkBIftPmeA+C04rxBJI2ip+MdmP+DltoVXNqJ9AzxZKqGdhq4zGCOzXxyZkqCn2n9r7bg+OoDK5QFrYzW9q9rciNAiEA8bBOQfBW9OOW7T69d8KEzJ9OYFDORaMzrDANW/6/Hd8CIQCgdWrVF3E5OzAwPA8/muBnoYp/BMNAu8saCKCHTL4MXwIgY29I0yIhdIFKL/N3GhWCc3k7Uq8MHmRltvrSFD47vPsCIH/YDZ5qZxOqTOKhd6S9yT3IP4ikSs0w0smTRhOG2YURAiA24bW9Q/0rvzigHlNL8mSvBRtyCsKWY2vuKb/QTBnM2A==";
        System.out.println("公钥：" + PUBLIC_KEY);
        System.out.println("私钥：" + PRIVATE_KEY);
        String wenjian =
                "ebnSXvJs7InoiRWAWCphos71EC6oGD42+FY653UZijPZKTaBNJcqe07Z8TsZdMj+SqKaUdhp0Bp9JBWiv2T/Sg==";
//      Thread
        String mw = "ebnSXvJs7InoiRWAWCphos71EC6oGD42+FY653UZijPZKTaBNJcqe07Z8TsZdMj+SqKaUdhp0Bp9JBWiv2T/Sg==";
        String wm = DbPasswordDigestUtils.decrypt(mw);
        System.out.println("原文：" + wenjian);
        System.out.println("密文：" + mw);
        System.out.println("明文：" + wm);

    }
}
